package limedia.sdk.api.realtime;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.SynchronousQueue;

import com.limedia.explorer.constant.Constant;
import com.limedia.explorer.enums.Enums.TSERTPlayState;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Environment;
import android.util.Log;

public class TSAudioDecoder {
	private static final String TAG = "TSVAudioDecoder";
	public MediaCodec mediaCodec;
	// format
	public MediaFormat mFormat;
	public Thread threadDecoder = null;
	public SynchronousQueue<TSPcmData> mPcmDatas = null;
	public boolean isDecoding = false;
	public int bufflength = 0;
	private AudioTrack audioTrack = null;
	private MediaExtractor extractor = null;;
	private long timestamp2;

	public TSAudioDecoder(SynchronousQueue<TSPcmData> queue) {
		// TODO Auto-generated constructor stub
		this.mPcmDatas = queue;
	}

	public TSERTPlayState initDecoder() {
		init();
		return TSERTPlayState.RT_PLAY_STATE_SUCCESS;
	}

	private int init() {
		// TODO Auto-generated method stub
		int minBufferSize = AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
				AudioFormat.ENCODING_PCM_16BIT);
		audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
				AudioFormat.ENCODING_PCM_16BIT, minBufferSize * 2, AudioTrack.MODE_STREAM);
		audioTrack.setStereoVolume(1.0f, 1.0f);
		audioTrack.play();
		extractor = new MediaExtractor();
		
		String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/IPCamera/abc.aac";
		try {
			extractor.setDataSource(path);
		} catch (IOException e1) {
			e1.printStackTrace();
			return -1;
		}

		try {
			MediaFormat format = extractor.getTrackFormat(0);
			mediaCodec = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME));
			mediaCodec.configure(format, null, null, 0);
			Log.d("xml", format.getString(MediaFormat.KEY_MIME));
			if (mediaCodec == null) {
				// Log.e(TAG, "Can't find audio info!!!!!!!!!!");
				return -1;
			}
			mediaCodec.start();
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
		return 0;
	}

	/**
	 * start decode
	 */
	public void start() {
		Log.i(TAG, "start");
		if (!this.isDecoding) {
			this.isDecoding = true;
			this.decode();
			Log.i(TAG, "start end");
		}
	}

	// strat to decode
	private void decode() {
		Log.i(TAG, "decode start");
		// valued decoder and start mian thread
		this.threadDecoder = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					doDecode();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		threadDecoder.start();
	}

	/**
	 * stop decode
	 */
	public void stop() {
		this.isDecoding = false;
		if (null != this.threadDecoder) {
			this.threadDecoder.interrupt();
			try {
				this.threadDecoder.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			this.threadDecoder = null;
		}
		// clear Queue
		if (null != mPcmDatas) {
			mPcmDatas.clear();
		}
	}

	/**
	 * release decode
	 */
	public void release() {
		if (this.isDecoding) {
			this.stop();
		}
		// clear Queue
		if (null != mPcmDatas) {
			mPcmDatas.clear();
			mPcmDatas = null;
		}
		// stop and release decoder
		if (null != mediaCodec) {
			this.mediaCodec.stop();
			this.mediaCodec.release();
			this.mediaCodec = null;
		}
		if (extractor != null) {
			extractor.release();
			extractor = null;
		}
	}

	private void doDecode() {

		MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

		while (isDecoding) {
			if (this.threadDecoder.isInterrupted()) {
				Log.i(TAG, "isInterrupted");
				break;
			}
			extractor.selectTrack(0);
			ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
			ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
			int inputBufferIndex = mediaCodec.dequeueInputBuffer(10000);
			if (inputBufferIndex >= 0) {

				TSPcmData pcmDataPop = null;
				ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
				inputBuffer.clear();
				try {
					if (null != mPcmDatas) {
						// Log.e("decodec", "get pcmdata before!");
						pcmDataPop = mPcmDatas.take();
						// Log.e("decodec", "get pcmdata success!");
					} else {
						Log.e(TAG, "mPcmDatas is null!");
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				inputBuffer.put(pcmDataPop.getPcm(), 0, pcmDataPop.getSize());
				// int sampleSize = extractor.readSampleData(inputBuffer, 0);
				// Log.d("xml","inputBufferindex"+inputBufferIndex+"inputbuffer"+inputBuffer.get(tmp.getData())+"inputbufferssize"+inputBuffers.length);
				mediaCodec.queueInputBuffer(inputBufferIndex, 0, pcmDataPop.getSize(), (timestamp2 * 1000000 / 30), 0);
				extractor.advance();
				timestamp2++;
			}
			int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
			if (outputBufferIndex == -1) {
				Constant.countnumber++;
			} else {
				Constant.countnumber = 0;
			}
			if (Constant.countnumber > 100 && Constant.isWithSevenByte) {
				Constant.isWithSevenByte = false;
			}
			while (outputBufferIndex >= 0) {
				ByteBuffer buf = outputBuffers[outputBufferIndex];
				byte[] chunk = new byte[bufferInfo.size];
				buf.get(chunk);
				buf.clear();
				// Log.d("AudioDecoder", chunk.length + " bytes decoded");
				if (chunk.length > 0) {
					audioTrack.write(chunk, 0, chunk.length);
				}
				mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
				outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
			}
		}
		
		
	}
	
}
